from django.db import models
from lab.models import Lab
from common.models import AccessionModel
from datetime import datetime
from django.contrib.auth.models import User
from lab.models import Researcher
import os
from django.core.exceptions import ValidationError
from django.core.files.storage import FileSystemStorage
from settings import FILE_DB_ROOT

class Committee(models.Model):
    name = models.CharField(max_length=20, unique=True)
    
    def __unicode__(self):
        return self.name
    

class Institution(models.Model):
    name = models.CharField(max_length=80, unique=True)
    
    def __unicode__(self):
        return self.name
    

class Protocol(AccessionModel):
    """a family of IRB-approval events (each event having a document) and data collection events (= experiments), all having institution + committee + reference_code in common (e.g.: Yale_HIC_0605001495). its a family of things that can differ in their approval year and revision within the approval year. ad-hoc correspondence (such as email or phone calls) can simply be referenced by date, and will not be as formal."""
    
    PATH_DEFAULT = ["{{ obj.lab.name }}", "{{ obj.name }}"]
    PATH_TYPE_DEFAULT = AccessionModel.DIR
    
    EVENTS_DIR = "events"
    REVISIONS_DIR = "revisions"
    
    SUBMITTED, ACTIVE, ANALYSIS, EXPIRED = range(4)
    STATUS_CHOICES = (
        (SUBMITTED, 'submitted'),
        (ACTIVE, 'active'),
        (ANALYSIS, 'analysis-only'),
        (EXPIRED, 'expired')
    )
    
    name = models.CharField(max_length=200, blank=True)
    date_added = models.DateField(auto_now_add=True, default=datetime.now)
    date_updated = models.DateField(auto_now=True, default=datetime.now)
    lab = models.ForeignKey(Lab)
    investigator = models.ForeignKey(Researcher, related_name='investigator')
    institution = models.ForeignKey(Institution)
    committee = models.ForeignKey(Committee)
    reference_code = models.CharField(max_length=100)
    protocol_status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES)
    researchers = models.ManyToManyField(Researcher)
    
    def __unicode__(self):
        return self.name
        
    def _setup_path(self, *args, **kwargs):
        """
        Add directories for events and revisions
        """
        os.mkdir(os.path.join(self._filedb.fullpath, self.EVENTS_DIR), 0744)
        os.mkdir(os.path.join(self._filedb.fullpath, self.REVISIONS_DIR), 0744)
        super(Protocol, self)._setup_path(*args, **kwargs)
    
    def clean(self, *args, **kwargs):
        """
        Autosets name to institution + committee + reference_code
        """
        self.name = "_".join([self.institution.name, self.committee.name, self.reference_code])
        super(Protocol, self).clean(*args, **kwargs)
    

class RevisionName(models.Model):
    name = models.CharField(max_length=100)

    def __unicode__(self):
        return self.name


class Revision(AccessionModel):
    PATH_DEFAULT = [
        "{{ obj.protocol.path}}",
        "{{ obj.protocol.REVISIONS_DIR }}",
        "y{{ obj.year|stringformat:'02i' }}-v{{ obj.version|stringformat:'02i' }}_{{ obj.name.name }}"
    ]
    PATH_TYPE_DEFAULT = AccessionModel.DIR
    
    protocol = models.ForeignKey(Protocol)
    name = models.ForeignKey(RevisionName)
    researcher = models.ForeignKey(Researcher, blank=True, null=True)
    year = models.PositiveIntegerField(default=1)
    version = models.PositiveIntegerField(default=1)
    date_created = models.DateField(auto_now_add=True, default=datetime.now)
    details = models.TextField()
    
    def __unicode__(self):
        return "%s - year %02i, version %02i - %s" % (
            self.protocol.name,
            self.year,
            self.version,
            self.name.name,
        )
    
    def clean(self, *args, **kwargs):
        """
        Overloaded function
        Autoset the 'year' and 'version' variables
        """
        # Only do this if a new entry
        if self.pk is None:
            # Find previous protocol revision if exists
            entry = Revision.objects.filter(protocol=self.protocol).order_by('year', 'version')
            if (len(entry)>0):
                entry = entry[len(entry)-1]
                if self.year > entry.year:
                    self.version = 1
                elif self.year == entry.year:
                    self.version = entry.version + 1
                else:
                    raise ValidationError('Year must be equal to or greater than %i' % entry.year)
            else:
                self.year = 1
                self.version = 1
        super(Revision, self).clean(*args, **kwargs)
    
    class Meta:
        unique_together = (('protocol', 'year', 'version'),)
    


def upload_revision_file(instance, filename):
    return os.path.join(instance.revision.path, filename)

fs = FileSystemStorage(location=FILE_DB_ROOT)

class RevisionFile(models.Model):    
    revision = models.ForeignKey(Revision)
    details = models.CharField(max_length=200, blank=True)
    filename = models.FileField(upload_to=upload_revision_file, storage=fs)
    
    def __unicode__(self):
        return self.filename.name
    

